#pragma once
#include "Shader.h"
#include "RenderCommand.h"
#include "OrthographicCamera.h"
#include "Hazel/Renderer/Texture.h"
#include "Hazel/Renderer/Ray.h"
#include "Camera.h"
#include "Scene.h"

namespace Hazel 
{

	class Renderer
	{
	public:

		static void Init();
		static void OnWindowResize(uint32_t width, uint32_t height);
		
		// ray tracing
		void OnResize(uint32_t width, uint32_t height);
		void Render(const Scene& scene,const Camera& camera);
		inline Ref<Texture2D> GetFinalImage() { return m_FinalImage; }

		struct Settings
		{
			bool Accumulate = true;
		};
		Settings& GetSettings() { return m_Settings; }
	private:
		struct HitPayload
		{
			float HitDistance;
			glm::vec3 WorldPosition;
			glm::vec3 WorldNormal;

			int ObjectIndex;
		};
		glm::vec4 PerPixel(uint32_t x, uint32_t y); // RayGen
		HitPayload TraceRay(const Ray& ray);
		HitPayload ClosestHit(const Ray& ray, float hitDistance, int objectIndex);
		HitPayload Miss(const Ray& ray); 

		uint32_t ConvertToRGBA(glm::vec4 color);

		uint32_t m_FrameIndex = 1;
		Settings m_Settings;

		std::vector<uint32_t> m_ImageHorizontalIter, m_ImageVerticalIter;
	public:
		void ResetFrameIndex() { m_FrameIndex = 1; }

		//---------------------------------------------------------------------
	public:
		static void BeginScene(OrthographicCamera& camera);
		static void EndScene();

		static void Submit(const Ref<VertexArray>& vertexArray, const Ref<Shader>& shader, const glm::mat4& transform = glm::mat4(1.0f));

		inline static RendererAPI::API GetAPI() { return RendererAPI::GetAPI(); }

		const Scene* m_ActivateScene = nullptr;
		const Camera* m_ActivateCamera = nullptr;
	private:
		struct SceneData
		{
			glm::mat4 ViewProjectionMatrix;
		};

		static SceneData* s_SceneData;
		// render image using texture
		Ref<Texture2D> m_FinalImage;
		uint32_t* m_imageData = nullptr;
		glm::vec4* m_AccumulationData = nullptr;


	};
}